package com.wlyy.starter.mybatis.expand;

import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
import com.wlyy.starter.mybatis.SQLUtil;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;

/**
 * 冲突更新，百度mysql 的ON DUPLICATE KEY UPDATE特性
 * <code>
 * INSERT INTO t_user (id,name,sex,create_time,update_time) VALUES ( ? , ? , ? , ? , ? ) ON DUPLICATE KEY UPDATE sex = VALUES(sex)
 * </code>
 */
public class InsertOrUpdate extends AbstractMethod {

    public final static String METHOD_ID = "insertOrUpdate";
    public InsertOrUpdate(String name) {
        super(name);
    }
    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        final String sqlTemp = "<script>INSERT INTO %s (%s) VALUES (%s) ON DUPLICATE KEY UPDATE %s</script>";

        final String tableName = tableInfo.getTableName();
        final String columnSql = SQLUtil.getAllColumn(tableInfo);
        final String fieldSql = SQLUtil.getAllField(tableInfo, EMPTY);
        final String updateValueSql = prepareUpdateSql(tableInfo);
        String sql = String.format(sqlTemp, tableName, columnSql, fieldSql, updateValueSql);
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
        return this.addInsertMappedStatement(mapperClass, modelClass, METHOD_ID, sqlSource,
                NoKeyGenerator.INSTANCE, tableInfo.getKeyProperty(), tableInfo.getKeyColumn());
    }

    private String prepareUpdateSql(TableInfo tableInfo) {
        StringBuilder updateSql = new StringBuilder("<trim prefixOverrides=\",\">");
        tableInfo.getFieldList().forEach(f -> updateSql.append(convertIf(", " + f.getColumn() + " = VALUES(" + f.getColumn() + ")", f)));
        return updateSql.append("</trim>").toString();
    }

    private String convertIf(final String sqlScript, TableFieldInfo tableField) {
        return convertIf(sqlScript, tableField.getProperty(), tableField.getUpdateStrategy(), tableField.isCharSequence());
    }

    private String convertIf(final String sqlScript, final String property, final FieldStrategy fieldStrategy, boolean isCharSequence) {
        if (fieldStrategy == FieldStrategy.NEVER) {
            return null;
        }
        if (fieldStrategy == FieldStrategy.IGNORED) {
            return sqlScript;
        }
        if (fieldStrategy == FieldStrategy.NOT_EMPTY && isCharSequence) {
            return SqlScriptUtils.convertIf(sqlScript, String.format("%s != null and %s != ''", property, property),
                    false);
        }
        return SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", property), false);
    }
}
